Gestionnaire de Mots de Passe Sécurisé avec SQLite et AES-GCM

Ce tutoriel vous guide à travers la création d'un gestionnaire de mots de passe sécurisé en Python, en utilisant SQLite pour le stockage et AES-GCM pour le chiffrement. Ce programme vous permet d'ajouter, récupérer, supprimer et mettre à jour des mots de passe de manière sécurisée.

Pré-requis :

Fonctionnalités du Programme :

Code Python :


import sqlite3
import json
import os
import base64
import hashlib
from getpass import getpass
from Crypto.Cipher import AES
from Crypto.Random import get_random_bytes
import requests
import secrets
import string

# Fichier de stockage sécurisé
DB_FILE = "password_manager.db"
KEY_FILE = "aes_key.bin"

# Vérifie si une clé existe, sinon la génère et la stocke
if not os.path.exists(KEY_FILE):
    AES_KEY = get_random_bytes(32)  # Utilisation d'une clé AES-256
    with open(KEY_FILE, "wb") as f:
        f.write(AES_KEY)
else:
    with open(KEY_FILE, "rb") as f:
        AES_KEY = f.read()

# Connexion à la base de données SQLite
def init_db():
    conn = sqlite3.connect(DB_FILE)
    cursor = conn.cursor()
    cursor.execute('''
        CREATE TABLE IF NOT EXISTS passwords (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            site TEXT NOT NULL,
            username TEXT NOT NULL,
            password TEXT NOT NULL
        )
    ''')
    conn.commit()
    conn.close()

# Fonction de chiffrement AES-GCM (plus sécurisé que CFB)
def encrypt_message(message):
    cipher = AES.new(AES_KEY, AES.MODE_GCM)
    ciphertext, tag = cipher.encrypt_and_digest(message.encode())
    return base64.b64encode(cipher.nonce + tag + ciphertext).decode()

# Fonction de déchiffrement
def decrypt_message(encrypted_message):
    try:
        encrypted_data = base64.b64decode(encrypted_message)
        nonce = encrypted_data[:16]
        tag = encrypted_data[16:32]
        ciphertext = encrypted_data[32:]
        cipher = AES.new(AES_KEY, AES.MODE_GCM, nonce=nonce)
        return cipher.decrypt_and_verify(ciphertext, tag).decode()
    except Exception as e:
        print("Erreur de déchiffrement :", e)
        return None

# Génération de mot de passe sécurisé
def generate_password(length=16):
    characters = string.ascii_letters + string.digits + string.punctuation
    return ''.join(secrets.choice(characters) for _ in range(length))

# Vérification de la sécurité du mot de passe (Have I Been Pwned)
def check_password_security(password):
    sha1_hash = hashlib.sha1(password.encode()).hexdigest().upper()
    prefix, suffix = sha1_hash[:5], sha1_hash[5:]
    response = requests.get(f'https://api.pwnedpasswords.com/range/{prefix}')
    if suffix in response.text:
        print("⚠️ Ce mot de passe a été compromis ! Choisissez un autre.")
    else:
        print("✅ Ce mot de passe est sécurisé.")

# Ajouter un mot de passe dans la base de données
def add_password():
    site = input("Nom du site : ")
    username = input("Nom d'utilisateur : ")
    password = getpass("Mot de passe (laisser vide pour générer un mot de passe sécurisé) : ")
    
    if not password:
        password = generate_password()
        print("Mot de passe généré :", password)
    
    encrypted_password = encrypt_message(password)
    
    conn = sqlite3.connect(DB_FILE)
    cursor = conn.cursor()
    cursor.execute("INSERT INTO passwords (site, username, password) VALUES (?, ?, ?)", (site, username, encrypted_password))
    conn.commit()
    conn.close()

    print(f"🔐 Mot de passe pour {site} ajouté avec succès.")

# Récupérer un mot de passe déchiffré
def retrieve_password():
    site = input("Nom du site à récupérer : ")
    conn = sqlite3.connect(DB_FILE)
    cursor = conn.cursor()
    cursor.execute("SELECT username, password FROM passwords WHERE site = ?", (site,))
    result = cursor.fetchone()
    conn.close()
    
    if result:
        username, encrypted_password = result
        decrypted_password = decrypt_message(encrypted_password)
        print(f"🔓 Identifiant : {username}\nMot de passe : {decrypted_password}")
    else:
        print("❌ Site non trouvé.")

# Supprimer un mot de passe
def delete_password():
    site = input("Nom du site à supprimer : ")
    conn = sqlite3.connect(DB_FILE)
    cursor = conn.cursor()
    cursor.execute("DELETE FROM passwords WHERE site = ?", (site,))
    conn.commit()
    conn.close()
    print(f"🗑️ Mot de passe pour {site} supprimé.")

# Mettre à jour un mot de passe
def update_password():
    site = input("Nom du site à mettre à jour : ")
    new_password = getpass("Nouveau mot de passe : ")
    encrypted_password = encrypt_message(new_password)
    
    conn = sqlite3.connect(DB_FILE)
    cursor = conn.cursor()
    cursor.execute("UPDATE passwords SET password = ? WHERE site = ?", (encrypted_password, site))
    conn.commit()
    conn.close()
    print(f"🔄 Mot de passe pour {site} mis à jour.")

if __name__ == "__main__":
    init_db()
    while True:
        print("\n1. Ajouter un mot de passe")
        print("2. Récupérer un mot de passe")
        print("3. Supprimer un mot de passe")
        print("4. Mettre à jour un mot de passe")
        print("5. Quitter")
        choix = input("Choisissez une option : ")
        
        if choix == "1":
            add_password()
        elif choix == "2":
            retrieve_password()
        elif choix == "3":
            delete_password()
        elif choix == "4":
            update_password()
        elif choix == "5":
            print("🔚 Fin du programme.")
            break
        else:
            print("❌ Option invalide, réessayez.")

        

Manuel d'Utilisation :

🚀 Lancer le Programme :

Pour exécuter le programme, ouvrez un terminal et lancez :

python gestionnaire_mdp_securise.py

📝 Options Disponibles :

⚠️ Attention Éthique :

Ce programme est destiné à un usage personnel et doit être utilisé pour gérer vos propres mots de passe de manière sécurisée. Veillez à toujours utiliser des mots de passe uniques pour chaque compte, à ne jamais partager vos mots de passe, et à les stocker dans un gestionnaire sécurisé. Ne stockez jamais vos mots de passe dans des fichiers non chiffrés ou en texte clair. 🔒